package com.xmhmyh.generalframework.project.sys.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.common.collect.Lists;
import com.xmhmyh.generalframework.common.BaseServiceImpl;
import com.xmhmyh.generalframework.common.constants.Constants;
import com.xmhmyh.generalframework.common.enums.ResponseCode;
import com.xmhmyh.generalframework.common.utils.MyBeanUtils;
import com.xmhmyh.generalframework.framework.exceptions.ManageExceptions;
import com.xmhmyh.generalframework.project.sys.conversion.Menu2MenuBtnVOConversion;
import com.xmhmyh.generalframework.project.sys.conversion.Menu2MenuVOConversion;
import com.xmhmyh.generalframework.project.sys.dto.MenuDTO;
import com.xmhmyh.generalframework.project.sys.entity.*;
import com.xmhmyh.generalframework.project.sys.enums.MenuType;
import com.xmhmyh.generalframework.project.sys.mapper.MenuMapper;
import com.xmhmyh.generalframework.project.sys.mapper.RoleMenuMapper;
import com.xmhmyh.generalframework.project.sys.service.IMenuService;
import com.xmhmyh.generalframework.project.sys.service.IRoleService;
import com.xmhmyh.generalframework.project.sys.vo.MenuBtnVO;
import com.xmhmyh.generalframework.project.sys.vo.MenuVO;
import com.xmhmyh.generalframework.project.sys.vo.MetaVo;
import com.xmhmyh.generalframework.project.sys.vo.RouterVo;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestBody;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: 于丁
 * @DateTime: 2020/7/24 9:09 上午
 */
@Service
public class MenuServiceImpl extends BaseServiceImpl<MenuMapper, Menu> implements IMenuService {

    @Autowired
    private IRoleService roleService;

    @Resource
    private RoleMenuMapper roleMenuMapper;


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveMenuHandler(User user, MenuDTO menuDTO) {
        // 判断是新增还是编辑
        Menu menu = new Menu();
        BeanUtils.copyProperties(menuDTO, menu);
        Boolean add = false;
        if (menuDTO.getId() == null) {
            add = true;
            // 新增
            MyBeanUtils.setSysInfo(menu, user.getId(), user.getAccountId());
            menu.setId(uidGenerator.getUID());
            menu.setMenuType(menuDTO.getMenuType());
            menu.setParentId(menuDTO.getParentId());
        }
        if (menu.getMenuType() == MenuType.LIST.getValue()) {
            menu.setPath("");
        }
        if (add) {
            save(menu);
            // 添加权限到超级管理员角色
            addMenuToSuperAdmin(menu.getId());
        } else {
            updateById(menu);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delHandler(Long id) {
        List<Menu> menuList = list();
        Menu menu = getById(id);
        // 先删除所有子菜单
        recursiveDel(menu, menuList);
        // 在删除自己
        removeById(id);
        delRoleMenuByMenuId(menu.getId());
    }

    /**
     * 递归删除所有的子类
     *
     * @param menu
     * @param privilegeList
     */
    private void recursiveDel(Menu menu, List<Menu> privilegeList) {
        Iterator<Menu> iterator = privilegeList.iterator();
        while (iterator.hasNext()) {
            Menu m = iterator.next();
            if (m.getParentId() != null && m.getParentId().equals(menu.getId())) {
                removeById(m.getId());
                recursiveDel(m, privilegeList);
                // 为所有角色删除此权限
                delRoleMenuByMenuId(m.getId());
            }
        }
    }

    /**
     * @Author: 于丁
     * @Description: 删除菜单所有的角色绑定
     * @DateTime: 2020/7/29 3:54 下午
     * @Params:
     * @Return
     */
    private void delRoleMenuByMenuId(Long menuId) {
        LambdaQueryWrapper<RoleMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(RoleMenu::getMenuId, menuId);
        roleMenuMapper.delete(queryWrapper);
    }

    /**
     * @Author: 于丁
     * @Description: 添加新增的菜单给超级管理员
     * @DateTime: 2020/7/29 1:54 下午
     * @Params:
     * @Return
     */
    private void addMenuToSuperAdmin(Long menuId) {
        Role role = roleService.findByRoleCode(Constants.SUPER_ROLE_NAME);
        if (role == null) {
            throw new ManageExceptions(ResponseCode.USERNAME_OR_PASSWORD_ERROR);
        }
        RoleMenu roleMenu = new RoleMenu();
        roleMenu.setMenuId(menuId);
        roleMenu.setRoleId(role.getId());
        roleMenuMapper.insert(roleMenu);
    }

    @Override
    public List<Menu> genMenuThreeByUserId(Long userId, MenuType maxType) {
        List<Menu> menuList = getMenuByUserId(userId);
        // 获取一级目录
        LambdaQueryWrapper<Menu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Menu::getParentId, Constants.MAIN_MENU_ID);
        List<Menu> parentsMenuList = list(queryWrapper);
        for (Menu menu : parentsMenuList) {
            recursionGetChildMenu(menu, menuList, maxType);
        }
        return parentsMenuList;
    }


    /**
     * @Author: 于丁
     * @Description: 递归查找子类
     * @DateTime: 2020/7/24 10:25 上午
     * @Params:
     * @Return
     */
    private void recursionGetChildMenu(Menu parentsMenu, List<Menu> allList, MenuType maxType) {
        if (parentsMenu.getMenuType() >= maxType.getValue()) {
            return;
        }
        Iterator<Menu> iterator = allList.iterator();
        while (iterator.hasNext()) {
            Menu menu = iterator.next();
            if (menu.getParentId().equals(parentsMenu.getId())) {
                parentsMenu.getChildList().add(menu);
                recursionGetChildMenu(menu, allList, maxType);
            }
        }

    }


    @Override
    public List<Menu> getMenuByRoleIds(List<Long> ids) {
        List<Menu> menuList = new ArrayList<>();
        // 根据角色获取权限
        List<RoleMenu> rolePermissionsList = roleService.getRoleMenusByRoleIds(ids);
        List<Long> menuIds = rolePermissionsList.stream().map(rolePermissions -> {
            return rolePermissions.getMenuId();
        }).collect(Collectors.toList());
        // 添加用户权限
        if (menuIds.size() == 0) {
            return menuList;
        }
        LambdaQueryWrapper<Menu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByAsc(Menu::getOrderNum);
        queryWrapper.in(Menu::getId, menuIds);
        menuList = (List<Menu>) list(queryWrapper);
        return menuList;
    }

    @Override
    public List<Menu> getMenuByUserId(Long userId) {
        List<Menu> menuList = new ArrayList<>();
        // 获取用户的角色
        List<UserRole> userRoles = roleService.getUserRolesByUserId(userId);
        if (userRoles.size() == 0) {
            return menuList;
        }
        List<Long> roleIds = userRoles.stream().map(userRole -> {
            return userRole.getRoleId();
        }).collect(Collectors.toList());
        if (roleIds.size() == 0) {
            return menuList;
        }
        menuList = getMenuByRoleIds(roleIds);
        return menuList;
    }


    /**
     * 是否为菜单内部跳转
     *
     * @param menu 菜单信息
     * @return 结果
     */
    public boolean isMeunFrame(Menu menu) {
        return menu.getMenuType() == MenuType.MENU.getValue();
    }


    @Override
    public List<MenuVO> getMenuListDataUser(Long userId) {
        // 获取所有权限
        List<Menu> menuList = genMenuThreeByUserId(userId, MenuType.BUTTON);
        List<MenuVO> menuVOList = recursiveConversion(menuList);
        return menuVOList;
    }

    /**
     * @Author: 于丁
     * @Description: 递归将menu转换成menuVo
     * @DateTime: 2020/7/28 3:17 下午
     * @Params:
     * @Return
     */
    public List<MenuVO> recursiveConversion(List<Menu> menus) {
        List<MenuVO> menuVOList = new ArrayList<>();
        for (Menu menu : menus) {
            MenuVO menuVO = Menu2MenuVOConversion. conversion(menu);
            menuVOList.add(menuVO);
            if (menu.getChildList().size() > 0) {
                menuVO.setChildren(recursiveConversion(menu.getChildList()));
            }
        }
        return menuVOList;
    }

    @Override
    public List<MenuBtnVO> getMenuBtnHandler(Map<Long, String> menuIdsMap, Long menuId) {
        // 获取当前用户的所有权限
        LambdaQueryWrapper<Menu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Menu::getMenuType, MenuType.BUTTON.getValue());
        queryWrapper.eq(Menu::getParentId, menuId);
        queryWrapper.orderByAsc(Menu::getOrderNum);
        List<Menu> menuList = list(queryWrapper);
        List<MenuBtnVO> menuBtnVOList = menuList.stream().map(menu -> {
            return Menu2MenuBtnVOConversion.conversion(menu);
        }).collect(Collectors.toList());
        // 去除不是用户权限内的按钮
        menuBtnVOList = menuBtnVOList.stream().filter(menuBtnVO -> {
            if (menuIdsMap.get(menuBtnVO.getId()) == null) {
                return false;
            }
            return true;
        }).collect(Collectors.toList());
        return menuBtnVOList;
    }


    @Override
    public Collection<TreeNode> buildMenuTree(Collection<Menu> menus) {
        return buildMenuTree(menus, true);
    }

    @Override
    public List<TreeNode> buildMenuTree(Collection<Menu> menus, Boolean isShowBtn) {
        List<TreeNode> treeNodes = Lists.newArrayList();
        if (CollectionUtils.isNotEmpty(menus)) {
            List<Menu> superPrivilegeList = Lists.newArrayList();
            for (Menu menu : menus) {
                if (menu.getParentId() == 0) {
                    superPrivilegeList.add(menu);
                }
            }
            if (CollectionUtils.isNotEmpty(superPrivilegeList)) {
                for (Menu superMenu : superPrivilegeList) {
                    menus.remove(superMenu);
                    TreeNode superTreeNode = new TreeNode();
                    superTreeNode.setId(superMenu.getId());
                    superTreeNode.setLabel(superMenu.getMenuName());
                    recursiveChildrenWithMemo(superTreeNode, menus, isShowBtn);
                    treeNodes.add(superTreeNode);
                }
            }
        }
        return treeNodes;
    }


    private void recursiveChildrenWithMemo(TreeNode comboTreeNode, Collection<Menu> privilegeList, Boolean isShowBtn) {
        for (Menu p : privilegeList) {
            if (!isShowBtn) {
                if (p.getMenuType() == MenuType.BUTTON.getValue()) {
                    continue;
                }
            }
            Long parentId = p.getParentId();
            if (parentId != null && parentId.equals(comboTreeNode.getId())) {
                TreeNode child = new TreeNode();
                child.setId(p.getId());
                child.setLabel(p.getMenuName());
                comboTreeNode.getChildren().add(child);
                comboTreeNode.setLeaf(false);
                recursiveChildrenWithMemo(child, privilegeList, isShowBtn);
            }
        }
    }

}
